<?php
/**
 * QuestionFeedbackRepo.php
 *
 * @copyright   2023 thingsworld.com.cn - All Rights Reserved
 * @link        http://thingsworld.com.cn/
 * @author      stiffer.chen <chenl@thingsworld.com.cn>
 * @created     2023-08-05 13:51:11
 * @modified    2023-08-05 13:51:11
 *
 */

namespace App\Repositories;

use App\Models\DeptModel;
use App\Models\DictDataModel;
use App\Models\Product;
use App\Models\Project;
use App\Models\QuestionFeedback;
use App\Models\QuestionFeedback\History;
use App\Models\QuestionFeedback\Image;
use App\Models\UserModel;
use App\Models\WorkOrder;
use App\Services\DeptService;
use App\Services\ImageServ;
use Carbon\Carbon;
use Illuminate\Support\Str;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

class QuestionFeedbackRepo
{
    // 探测度
    const PARAM_DETECTIVITY = '质量反馈-探测度';
    // 问题等级
    const PARAM_LEVEL = '质量反馈-问题等级';
    // 异常等级
    const PARAM_EXCEPTION_LEVEL = '质量反馈-异常等级';
    // 问题归类
    const PARAM_CATEGORY = '质量反馈-问题归类';
    // 生产基地
    const PARAM_BASE = '生产基地';

    const STATUS_CREATE = 'create'; // 已创建
    const STATUS_RESOLVED = 'resolved'; // 已解决
    const STATUS_AUDIT = 'audit'; // 区域经理已审核(反馈至品质部)
    const STATUS_AUDIT_QUANTITY = 'audit_manager'; // 品质工程师已审核
    const STATUS_PROCESSED = 'processed'; // 反馈人已处理
    const STATUS_CLOSED = 'closed'; // 已关闭

    const ROLE_ENGINEER = '工程师';
    const ROLE_MANAGER = '区域经理';
    const ROLE_QUANTITY_MANAGER = '品质工程师';
    const ROLE_AUDIT = '审核者';

    const TITLE_NOTIFY = '质量反馈通知';
    const CONTENT_CREATE = '您有一条质量反馈待审核，请及时审核';
    const CONTENT_UN_AUDIT = '您有一条质量反馈待解决，请及时解决';
    const CONTENT_QUANTITY = '您有一条质量反馈已被品质工程师处理，请及时查看';
    const CONTENT_RESOLVED = '您有一条质量反馈已解决, 请及时查看';
    const CONTENT_UN_CLOSED = '您有一条质量反馈待关闭，请及时查看';
    const CONTENT_CLOSED = '您有一条质量反馈已关闭，请及时查看';

    const STATUS_RESOLVED_CODE = 'resolved';
    const STATUS_AUDIT_TITLE = '已审核';
    const STATUS_AUDIT_MANAGER_TITLE = '已审核';
    const STATUS_RESOLVED_TITLE = '已解决';
    const STATUS_UN_RESOLVE_CODE = 'un_resolve';
    const STATUS_UN_RESOLVE_TITLE = '未解决';
    const STATUS_UN_PROCESS_CODE = 'un_process';
    const STATUS_UN_PROCESS_TITLE = '未处理';

    const RESULT_CLOSED_CODE = 'closed';
    const RESULT_CLOSED_TITLE = '已关闭';
    const RESULT_UN_CLOSE_CODE = 'un_close';
    const RESULT_UN_CLOSE_TITLE = '未关闭';


    const COMMENT_CLOSED = '区域经理关闭了问题反馈';
    const COMMENT_AUDIT = '区域经理审核了问题反馈';
    const COMMENT_QUANTITY_AUDIT = '品质工程师处理了问题反馈';
    const COMMENT_ACTION = '反馈人处理了问题反馈';

    public static function getList()
    {
        $dateParams = self::dateParams();
        $start = $dateParams['start'] ?? '';
        $end = $dateParams['end'] ?? '';
        $params = self::params();
        $level = trim(request('level', ''));
        $levels = $params['level'] ?? [];
        if (!in_array($level, $levels)) {
            $level = '';
        }
        $source = trim(request('source', ''));
        if (!in_array($source, ['work_order', 'project'])) {
            $source = '';
        }
        $statuses = collect($params['status'])->pluck('code')->toArray();
        $status = trim(request('status', ''));
        if (!in_array($status, $statuses)) {
            $status = '';
        }
        $results = collect($params['result'])->pluck('code')->toArray();
        $result = trim(request('result', ''));
        if (!in_array($result, $results)) {
            $result = '';
        }
        $perPage = (int)request('limit');
        if ($perPage < 1) {
            $perPage = 10;
        }

        $projectID = intval(request('project_id', ''));

        $qfNumber = trim(request('qf_number', ''));

        $builder = QuestionFeedback::query();
        $builder->with(['images', 'histories.user']);

        if ($qfNumber) {
            $builder->where('qf_number', 'like', "%{$qfNumber}%");
        }

        if ($level) {
            $builder->where('question_level', $level);
        }
        if ($source == 'work_order') {
            $builder->where('wo_id', '>', 0);
        }
        if ($source == 'project') {
            $builder->where('project_id', '>', 0);
        }

        if ($projectID) {
            $builder->where('project_id', '=', $projectID);
        }

        $filterStatus = [];
        if ($status == self::STATUS_RESOLVED) {
            $filterStatus = [self::STATUS_RESOLVED];
        }
        if ($status == self::STATUS_UN_PROCESS_CODE) {
            $filterStatus = [
                self::STATUS_CREATE
            ];
        }
        if ($status == self::STATUS_UN_RESOLVE_CODE) {
            $filterStatus = [self::STATUS_RESOLVED];
        }

        if ($filterStatus) {
            $builder->whereIn('status', $filterStatus);
        }

        if ($result == self::RESULT_CLOSED_CODE) {
            $filterStatus = [self::STATUS_CLOSED];
        }
        if ($status == self::RESULT_UN_CLOSE_CODE) {
            $filterStatus = [
                self::STATUS_RESOLVED_CODE,
                self::STATUS_UN_RESOLVE_CODE,
                self::STATUS_UN_PROCESS_CODE
            ];
        }

        if ($filterStatus) {
            $builder->whereIn('status', $filterStatus);
        }

        if ($start) {
            $start = strtotime($start);
            $builder->where('create_time', '>=', $start);
        }

        if ($end) {
            $end = strtotime($end);
            $builder->where('create_time', '<=', $end);
        }

        $builder->orderByDesc('update_time');
        $builder->orderByDesc('create_time');
        $export = intval(request('export', 0));
        if ($export) {
            $dataResult = $builder->get();
        } else {
            $dataResult = $builder->paginate($perPage);
            $dataResult->transform(function ($item) {
                return self::getInfo($item);
            });
        }
        if ($export) {
            $exportData = [];
            foreach ($dataResult as $item) {
                $exportData[] = self::getInfo($item);
            }
            return self::export($exportData ?? []);
        }
        return $dataResult;
    }

    private static function dateParams()
    {
        $dateType = trim(request('date_type', ''));
        $dateStart = trim(request('month_start', ''));
        $dateEnd = trim(request('month_end', ''));
        $types = array_keys(collect(ReportsRepo::types())->keyBy('code')->toArray());
        if (!in_array($dateType, $types)) {
            return [];
        }
        if (!$dateType) {
            return [];
        }
        if ($dateType == ReportsRepo::TYPE_MONTH_SELECT && (!$dateStart || !$dateEnd)) {
            return [];
        }
        $start = '';
        $end = '';
        switch ($dateType) {
            case ReportsRepo::TYPE_WEEK:
                $start = Carbon::now()->startOfWeek()->toDateTimeString();
                $end = Carbon::now()->endOfWeek()->toDateTimeString();
                break;
            case ReportsRepo::TYPE_MONTH:
                $start = Carbon::now()->startOfMonth()->toDateTimeString();
                $end = Carbon::now()->endOfMonth()->toDateTimeString();
                break;
            case ReportsRepo::TYPE_QUARTER:
                $quarterData = self::getQuarterDate();
                $start = $quarterData['start'];
                $end = $quarterData['end'];
                break;
            case ReportsRepo::TYPE_YEAR:
                $start = Carbon::now()->startOfYear()->toDateTimeString();
                $end = Carbon::now()->endOfYear()->toDateTimeString();
                break;
            case ReportsRepo::TYPE_MONTH_SELECT:
                try {
                    $start = Carbon::parse($dateStart)->startOfMonth()->toDateTimeString();
                } catch (\Exception $e) {
                    $start = '';
                }
                try {
                    $end = Carbon::parse($dateEnd)->endOfMonth()->toDateTimeString();
                } catch (\Exception $e) {
                    $end = '';
                }
        }
        return [
            'start' => $start,
            'end' => $end
        ];
    }

    private static function getQuarterDate()
    {
        $now = Carbon::now();
        $currentYear = $now->year;
        $currentMonth = $now->month;
        $currentQuarter = intval(ceil($currentMonth / 3));
        $start = '';
        $end = '';
        switch ($currentQuarter) {
            case 1:
                $start = Carbon::parse($currentYear . "-01")->startOfMonth()->toDateTimeString();
                $end = Carbon::parse($currentYear . "-03")->endOfMonth()->toDateTimeString();
                break;
            case 2:
                $start = Carbon::parse($currentYear . "-04")->startOfMonth()->toDateTimeString();
                $end = Carbon::parse($currentYear . "-06")->endOfMonth()->toDateTimeString();
                break;
            case 3:
                $start = Carbon::parse($currentYear . "-07")->startOfMonth()->toDateTimeString();
                $end = Carbon::parse($currentYear . "-09")->endOfMonth()->toDateTimeString();
                break;
            case 4:
                $start = Carbon::parse($currentYear . "-10")->startOfMonth()->toDateTimeString();
                $end = Carbon::parse($currentYear . "-12")->endOfMonth()->toDateTimeString();
                break;
        }
        return ['start' => $start, 'end' => $end];
    }

    // 导出数据
    private static function export($qfs)
    {
        $pathPrefix = 'downloads/question_feedback/' . date('Y/m/d/');
        $prefix = public_path() . '/' . $pathPrefix;
        $excelFileName = 'qf-' . md5(date('YmdHis') . microtime()) . '.xlsx';
        if (!is_dir($prefix)) {
            mkdir($prefix, 0777, true);
        }
        $excelFilePath = $prefix . $excelFileName;
        $spreadsheet = new Spreadsheet();
        $sheet = new Worksheet($spreadsheet, "质量反馈");
        $spreadsheet->addSheet($sheet);
        $spreadsheet->removeSheetByIndex(0);

        // 填充数据
        $excelData = [];
        $excelData[] = [
            '序号',
            '反馈编号',
            '订单号',
            '反馈人',
            '反馈时间',
            '质保开始时间',
            '设备运行时间(天)',
            '区域经理',
            '',
            '',
            '品质部',
            '',
            '',
            '',
            '',
            '',
            '解决状态',
            '',
            '反馈结果',
            '',
            '问题归类',
            '',
            '问题等级',
            '是否验收',
            '客户信息',
            '生产基地',
            '异常图片',
            '异常数量',
            '异常等级',
            '探测度',
            '异常设备',
            '设备编号',
            '原因分析',
            '临时措施',
            '是否更换配件',
            '项目名称'
        ];
        $excelData[] = [
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            // 区域经理
            '负责人',
            '审核时间',
            '处理意见',
            // 品质部
            '负责人',
            '处理时间',
            '备件是否退回',
            '改善措施',
            '原因分析',
            '临时措施',
            // 解决状态
            '是否解决',
            '解决时间',
            // 反馈结果
            '是否关闭',
            '关闭时间',
            // 问题归类
            '分类',
            '细分',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
            '',
        ];

        foreach ($qfs as $index => $qf) {
            $projectId = $qf['project_id'] ?? 0;
            $project = Project::find($projectId);
            $key = $index + 1;
            $runtime = '';
            $bootTime = $qf['boot_time'];
            if ($bootTime) {
                try {
                    $runtime = Carbon::parse($bootTime)->diffInDays(Carbon::now());
                } catch (\Exception $e) {
                    $runtime = '';
                }
            }
            $isReturn = $qf['is_return'] ? "是" : '否';
            $excelData[] = [
                ' ' . $key,
                ' ' . $qf['qf_number'] ?? '',
                ' ' . $qf['order_number'] ?? '',
                ' ' . $qf['user_name'] ?? '',
                ' ' . $qf['create_time'] ?? '',
                ' ' . $qf['warranty_start'] ?? '', // 质保开始时间
                ' ' . $runtime, // 设备运行时间
                ' ' . $qf['manager_name'] ?? '',
                ' ' . $qf['suggestion_manager_time'] ?? '',
                ' ' . $qf['suggestion_manager'] ?? '',
                // 品质部
                ' ' . $qf['quantity_user_name'] ?? '',
                ' ' . $qf['quantity_update_time'] ?? '',
                ' ' . $isReturn, // 备件是否退回
                ' ' . $qf['improve'] ?? '',
                ' ' . $qf['reason'] ?? '',
                ' ' . $qf['measure_temp'] ?? '',
                $qf['resolved'] ? ' 是' : ' 否',
                ' ' . $qf['resolve_time'] ?? '',
                $qf['closed'] ? ' 是' : ' 否',
                ' ' . $qf['close_time'],
                ' ' . $qf['question_type'],
                ' ' . $qf['question_type_detail'],
                ' ' . $qf['question_level'],
                $qf['checked'] ? ' 是' : ' 否',
                ' ' . $qf['customer_name'],
                ' ' . $qf['production_base'],
                ' ', // 图片
                ' ' . $qf['quantity'],
                ' ' . $qf['exception_level'],
                ' ' . $qf['detectivity'],
                ' ' . $qf['product_name'],
                ' ' . $qf['product_number'],
                ' ' . $qf['reason'],
                ' ' . $qf['measure_temp'],
                $qf['bom_replace'] ? ' 是' : ' 否',
                $project->name ?? ''
            ];
        }

        $sheet->fromArray($excelData);

        foreach ($qfs as $index => $qf) {
            $key = $index + 2;
            $imagePaths = $qf['image_paths'];
            if (!$imagePaths) {
                continue;
            }
            $imagePath = $imagePaths[0];
            if (!is_file(public_path('/') . $imagePath)) {
                $imagePath = 'images/placeholder.png';
            }
            $path = public_path('/') . $imagePath;
            if (!is_file($path)) {
                continue;
            }
            $cellIndex = "AA{$key}";
            $drawing = new Drawing();
            $drawing->setName('aaa');
            $drawing->setDescription('bbb');
            $drawing->setPath($path);
            $drawing->setHeight(36);
            $drawing->setCoordinates($cellIndex);
            $drawing->setOffsetX(10);
            $drawing->setWorksheet($sheet);
        }

        self::setHeaderStyle($sheet);

        $writer = new Xlsx($spreadsheet);
        $writer->save($excelFilePath);
        return env('APP_URL') . '/' . $pathPrefix . $excelFileName;
    }

    private static function setHeaderStyle($sheet)
    {
        // 合并表头
        $sheet->mergeCellsByColumnAndRow(1, 1, 1, 2);
        $sheet->mergeCellsByColumnAndRow(2, 1, 2, 2);
        $sheet->mergeCellsByColumnAndRow(3, 1, 3, 2);
        $sheet->mergeCellsByColumnAndRow(4, 1, 4, 2);
        $sheet->mergeCellsByColumnAndRow(5, 1, 5, 2);
        $sheet->mergeCellsByColumnAndRow(6, 1, 6, 2);
        $sheet->mergeCellsByColumnAndRow(7, 1, 7, 2);
        // 区域经理
        $sheet->mergeCellsByColumnAndRow(8, 1, 10, 1);
        // 品质部
        $sheet->mergeCellsByColumnAndRow(11, 1, 16, 1);
        // 解决状态
        $sheet->mergeCellsByColumnAndRow(16, 1, 18, 1);
        // 反馈结果
        $sheet->mergeCellsByColumnAndRow(19, 1, 20, 1);
        // 问题归类
        $sheet->mergeCellsByColumnAndRow(21, 1, 22, 1);

        $sheet->mergeCellsByColumnAndRow(23, 1, 23, 2);
        $sheet->mergeCellsByColumnAndRow(24, 1, 24, 2);
        $sheet->mergeCellsByColumnAndRow(25, 1, 25, 2);
        $sheet->mergeCellsByColumnAndRow(26, 1, 26, 2);
        $sheet->mergeCellsByColumnAndRow(27, 1, 27, 2);
        $sheet->mergeCellsByColumnAndRow(28, 1, 28, 2);
        $sheet->mergeCellsByColumnAndRow(29, 1, 29, 2);
        $sheet->mergeCellsByColumnAndRow(30, 1, 30, 2);
        $sheet->mergeCellsByColumnAndRow(31, 1, 31, 2);
        $sheet->mergeCellsByColumnAndRow(32, 1, 32, 2);
        $sheet->mergeCellsByColumnAndRow(33, 1, 33, 2);
        $sheet->mergeCellsByColumnAndRow(34, 1, 34, 2);
        $sheet->mergeCellsByColumnAndRow(35, 1, 35, 2);
        $sheet->mergeCellsByColumnAndRow(36, 1, 36, 2);

        // 单个不合并
        self::mergeCellTopToBottom($sheet, 'A', 'G');
        /**
         * 合并区域经理(H~J)
         * 背景色 + 边框 + 左右居中 + 上下居中
         */
        self::mergeCellLeftToRight($sheet, 'H', 'J');

        self::setCellStyle($sheet, 'H', 2);
        self::setCellStyle($sheet, 'I', 2);
        self::setCellStyle($sheet, 'J', 2);

        /**
         * 合并品质工程师(k~p)
         * 背景色 + 边框 + 左右居中 + 上下居中
         */
        self::mergeCellLeftToRight($sheet, 'K', 'P');
        self::setCellStyle($sheet, 'K', 2);
        self::setCellStyle($sheet, 'L', 2);
        self::setCellStyle($sheet, 'M', 2);
        self::setCellStyle($sheet, 'N', 2);
        self::setCellStyle($sheet, 'O', 2);
        self::setCellStyle($sheet, 'P', 2);

        /**
         * 合并解决状态(Q~R)
         * 背景色 + 边框 + 左右居中 + 上下居中
         */
        self::mergeCellLeftToRight($sheet, 'Q', 'R');
        self::setCellStyle($sheet, 'Q', 2);
        self::setCellStyle($sheet, 'R', 2);
        /**
         * 合并反馈结果(S~T)
         * 背景色 + 边框 + 左右居中 + 上下居中
         */
        self::mergeCellLeftToRight($sheet, 'S', 'T');
        self::setCellStyle($sheet, 'S', 2);
        self::setCellStyle($sheet, 'T', 2);
        /**
         * 合并问题归类(U~V)
         * 背景色 + 边框 + 左右居中 + 上下居中
         */
        self::mergeCellLeftToRight($sheet, 'U', 'V');
        self::setCellStyle($sheet, 'U', 2);
        self::setCellStyle($sheet, 'V', 2);

        self::mergeCellTopToBottom($sheet, 'W', 'Z');
        self::mergeCellTopToBottom($sheet, 'AA', 'AJ');
    }

    private static function mergeCellTopToBottom($sheet, $from, $to)
    {
        for ($i = $from; $i <= $to; $i++) {
            $columnStr = "{$i}1:{$i}2";
            $sheet->getStyle($columnStr)->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setARGB('343434');
            $sheet->getStyle($columnStr)->getBorders()->getOutline()->setBorderStyle(Border::BORDER_THIN)->setColor(new Color('000000'));
            $sheet->getStyle($columnStr)->getFont()->getColor()->setARGB('FFFFFF');
            $sheet->getStyle($columnStr)->getAlignment()->setHorizontal('center');
            $sheet->getStyle($columnStr)->getAlignment()->setVertical('center');
        }
        return $sheet;
    }

    private static function mergeCellLeftToRight($sheet, $left, $right)
    {
        $columnStr = "{$left}1:{$right}1";
        $sheet->getStyle($columnStr)->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setARGB('343434');
        $sheet->getStyle($columnStr)->getBorders()->getOutline()->setBorderStyle(Border::BORDER_THIN)->setColor(new Color('000000'));
        $sheet->getStyle($columnStr)->getFont()->getColor()->setARGB('FFFFFF');
        $sheet->getStyle($columnStr)->getAlignment()->setHorizontal('center');
        $sheet->getStyle($columnStr)->getAlignment()->setVertical('center');
        return $sheet;
    }

    private static function setCellStyle($sheet, $column, $row)
    {
        $columnStr = "{$column}{$row}:{$column}{$row}";
        $sheet->getStyle($columnStr)->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setARGB('343434');
        $sheet->getStyle($columnStr)->getBorders()->getOutline()->setBorderStyle(Border::BORDER_THIN)->setColor(new Color('000000'));
        $sheet->getStyle($columnStr)->getFont()->getColor()->setARGB('FFFFFF');
        $sheet->getStyle($columnStr)->getAlignment()->setHorizontal('center');
        $sheet->getStyle($columnStr)->getAlignment()->setVertical('center');
        return $sheet;
    }

    // 所需参数获取
    public static function params()
    {
        // 探测度、问题等级
        $params = DictDataModel::query()
            ->from('dict_data as dd')
            ->join('dict as d', 'd.id', '=', 'dd.dict_id')
            ->whereIn('d.name', [self::PARAM_LEVEL, self::PARAM_DETECTIVITY, self::PARAM_CATEGORY, self::PARAM_EXCEPTION_LEVEL, self::PARAM_BASE])
            ->select(['dd.name', 'd.name as p_name', 'dd.detail'])
            ->get();
        $simpleParams = $params->groupBy('p_name')->toArray();
        $detectivities = collect($simpleParams[self::PARAM_DETECTIVITY] ?? [])->pluck('name')->toArray();
        $levels = collect($simpleParams[self::PARAM_LEVEL] ?? [])->pluck('name')->toArray();
        $exceptionLevels = collect($simpleParams[self::PARAM_EXCEPTION_LEVEL] ?? [])->pluck('name')->toArray();
        $productionBase = collect($simpleParams[self::PARAM_BASE] ?? [])->pluck('name')->toArray();

        $categoryParam = $simpleParams[self::PARAM_CATEGORY] ?? [];

        $categories = [];

        foreach ($categoryParam as $item) {
            $categoryName = $item['name'];
            $itemDetails = explode("\n", preg_replace('~\r?\n~', "\n", $item['detail'] ?? ''));
            $categories[] = [
                'name' => $categoryName,
                'detail' => $itemDetails
            ];
        }

        return [
            'production_base' => $productionBase,
            'detectivity' => $detectivities,
            'level' => $levels,
            'exception_level' => $exceptionLevels,
            'question_category' => $categories,
            'status' => [
                ['code' => self::STATUS_RESOLVED_CODE, 'title' => self::STATUS_RESOLVED_TITLE],
                ['code' => self::STATUS_UN_RESOLVE_CODE, 'title' => self::STATUS_UN_RESOLVE_TITLE],
                ['code' => self::STATUS_UN_PROCESS_CODE, 'title' => self::STATUS_UN_PROCESS_TITLE],
            ],
            'result' => [
                ['code' => self::RESULT_CLOSED_CODE, 'title' => self::RESULT_CLOSED_TITLE],
                ['code' => self::RESULT_UN_CLOSE_CODE, 'title' => self::RESULT_UN_CLOSE_TITLE]
            ],
            'source' => [
                ['code' => 'work_order', 'title' => '工单'],
                ['code' => 'project', 'title' => '项目']
            ]
        ];
    }

    // 待处理数量
    // 非区域经理和品质工程师 => 0
    public static function unProcessCount()
    {
        $user = registry('user');
        $userId = $user->id ?? 0;
        $userDeptId = $user->dept_id ?? 0;
        // 是否是品质工程师
        $isQuantityEngineer = (new DeptService())->isQuantityEngineer($userDeptId);
        // 是否是区域经理
        $isManagerEngineer = (new DeptService())->isManagerEngineer($userId);

        if (!$isQuantityEngineer && !$isManagerEngineer) {
            // return 0;
        }
        // 超级管理员
        if ($userId == 1) {
            $count = QuestionFeedback::query()
                ->where(function ($query) use ($userId) {
                    $query->where('status', '=', self::STATUS_CREATE)
                        ->where('manager_id', '=', $userId);
                })
                ->orWhere(function ($query) use ($userId) {
                    $query->where('status', '=', self::STATUS_AUDIT)
                        ->where('manager_id', '=', $userId);
                })
                ->count();
            return $count;
        }
        // 区域经理未处理数量
        $managerUnProcessCount = QuestionFeedback::query()
            ->where('status', '=', self::STATUS_CREATE)
            ->where('manager_id', '=', $userId)
            ->count();

        // 品质工程师未处理
        $quantityUnProcessCount = QuestionFeedback::query()
            ->where('status', '=', self::STATUS_AUDIT)
            ->where('quantity_user_id', '=', $userId)
            ->count();

        if ($isManagerEngineer) {
            return $managerUnProcessCount;
        }
        if ($isQuantityEngineer) {
            return $quantityUnProcessCount;
        }
        return 0;
    }

    // 质量反馈提交
    public static function store()
    {
        $data = self::validate();
        $user = registry('user');

        $mainData = $data['main'];
        $images = $data['images'];
        $history = $data['history'];

        $dbHistory = new History($history);
        $dbImages = [];
        foreach ($images as $image) {
            $dbImages[] = new Image([
                'image' => trim(strval($image))
            ]);
        }

        $qf = new QuestionFeedback();
        $qf->fill($mainData);
        $qf->saveOrFail();
        $qf->histories()->save($dbHistory);
        $qf->images()->saveMany($dbImages);

        $qfId = $qf->id;
        $acceptId = $mainData['manager_id'];
        $actorUserName = $mainData['manager_name'];
        $actorRoleName = self::ROLE_ENGINEER;
        $title = self::TITLE_NOTIFY;
        $content = self::CONTENT_CREATE;
        self::notifyMessage($qfId, $acceptId, $actorUserName, $actorRoleName, $title, $content);

        return self::getDetail($qf->id);
    }

    // @todo 反馈详情
    public static function getDetail($id)
    {
        $qf = QuestionFeedback::find($id);
        if (empty($qf)) {
            throw new \Exception('反馈详情不存在');
        }
        $qf->with(['images', 'histories.user']);
        return self::getInfo($qf);
    }

    public static function getInfo($detail)
    {
        $images = $detail->images;
        $histories = $detail->histories;
        $qfImages = [];
        $qfHistories = [];
        if ($histories->count()) {
            foreach ($histories as $history) {
                $comment = json_decode($history->comment, true);
                $status = $history->status;
                $statusText = '';
                switch ($status) {
                    case self::STATUS_CREATE:
                        $statusText = '已创建';
                        break;
                    case self::STATUS_CLOSED:
                        $statusText = '已关闭';
                        break;
                    case self::STATUS_RESOLVED:
                        $statusText = '已解决';
                        break;
                    case self::STATUS_PROCESSED:
                        $statusText = '已处理';
                        break;
                }
                $qfHistories[] = [
                    'status' => $status,
                    'status_text' => $statusText,
                    'comment' => $comment,
                    'create_time' => Carbon::parse($history->create_time)->toDateTimeString(),
                    'update_time' => Carbon::parse($history->update_time)->toDateTimeString(),
                ];
            }
        }
        if ($images->count()) {
            foreach ($images as $image) {
                $qfImages[] = (new ImageServ($image->image))->getUrl();
            }
        }

        $imagePaths = [];
        foreach ($images as $image) {
            $imagePaths[] = $image->image;
        }

        $qfStatus = $detail->status;
        $qfStatusText = '';
        switch ($qfStatus) {
            case self::STATUS_CREATE:
                $qfStatusText = '已创建';
                break;
            case self::STATUS_CLOSED:
                $qfStatusText = '已关闭';
                break;
            case self::STATUS_RESOLVED:
                $qfStatusText = '已解决';
                break;
            case self::STATUS_PROCESSED:
                $qfStatusText = '已处理';
                break;
            case self::STATUS_AUDIT:
                $qfStatusText = self::STATUS_AUDIT_TITLE;
                break;
            case self::STATUS_AUDIT_QUANTITY:
                $qfStatusText = self::STATUS_AUDIT_MANAGER_TITLE;
                break;
        }

        $managerActionTime = '';
        $quantityActionTime = '';
        $resolved = boolval($detail->resolved);
        $resolveTime = $detail->resolve_time;

        $status = $detail->status;
        $closed = false;
        $closeTime = '';
        if ($status == self::STATUS_CLOSED) {
            $closed = true;
            $closeTime = Carbon::parse($detail->update_time)->toDateTimeString();
        }

        // 是否已处理
        $acted = false;
        // 反馈者是否已处理
        $showUserAction = false;

        foreach ($qfHistories as $history) {
            $historyComment = $history['comment']['comment'] ?? '';
            $historyTime = Carbon::parse($history['create_time'])->toDateTimeString();
            if ($historyComment == self::COMMENT_AUDIT) {
                $managerActionTime = $historyTime;
            }
            if ($historyComment == self::COMMENT_QUANTITY_AUDIT) {
                $quantityActionTime = $historyTime;
                $acted = true;
            }
            if ($historyComment == self::COMMENT_ACTION) {
                $acted = true;
                $showUserAction = true;
            }
        }

        $runTime = '';
        $bootTime = $detail->boot_time;
        if ($bootTime) {
            try {
                $bootTime = Carbon::parse($bootTime)->toDateString();
            } catch (\Exception $e) {
                $bootTime = '';
            }
        }

        if ($bootTime) {
            $runTime = Carbon::now()->diffInDays($bootTime);
        }

        $result = [
            'id' => $detail->id,
            'manager_action_time' => $managerActionTime,
            'quantity_action_time' => $quantityActionTime,
            'resolved' => $resolved,
            'resolve_time' => $resolveTime,
            'closed' => $closed,
            'close_time' => $closeTime,
            'btn_quantity_audit' => $detail->btn_quantity_audit,
            'btn_engineer_process' => $detail->btn_engineer_process,
            'btn_close' => $detail->btn_close,
            'btn_engineer_to' => $detail->btn_engineer_to,
            'qf_number' => $detail->qf_number,
            'user_id' => $detail->user_id,
            'user_name' => $detail->user_name,
            'wo_id' => $detail->wo_id,
            'wo_number' => $detail->wo_number,
            'project_id' => $detail->project_id,
            'project_number' => $detail->project_number,
            'order_number' => $detail->order_number,
            'checked' => boolval($detail->checked),
            'is_quality' => boolval($detail->is_quality),
            'product_id' => $detail->product_id,
            'product_name' => $detail->product_name,
            'product_number' => $detail->product_number,
            'product_date' => $detail->product_date,
            'quantity' => $detail->quantity,
            'production_base' => $detail->production_base,
            'question_level' => $detail->question_level,
            'exception_level' => $detail->exception_level,
            'question_type' => $detail->question_type,
            'question_type_detail' => $detail->question_type_detail,
            'bom_replace' => boolval($detail->bom_replace),
            'customer_name' => $detail->customer_name,
            'manager_id' => $detail->manager_id,
            'manager_name' => $detail->manager_name,
            'quantity_user_id' => $detail->quantity_user_id,
            'quantity_user_name' => $detail->quantity_user_name,
            'description' => $detail->description,
            'reason' => $detail->reason,
            'measure_temp' => $detail->measure_temp,
            'suggestion_manager' => $detail->suggestion_manager,
            'suggestion_manager_time' => $detail->suggestion_manager_time,
            'dept_id' => $detail->dept_id,
            'dept_name' => $detail->dept_name,
            'charge_user_id' => $detail->charge_user_id,
            'charge_user_name' => $detail->charge_user_name,
            'improve' => $detail->improve,
            'suggestion' => $detail->suggestion,
            'measure_reason' => $detail->measure_reason,
            'measure_temp_scene' => $detail->measure_temp_scene,
            'detectivity' => $detail->detectivity,
            'resolve_content' => $detail->resolve_content,
            'quantity_update_time' => $detail->quantity_update_time,
            'show_user_action' => $showUserAction,
            'status' => $qfStatus,
            'status_text' => $qfStatusText,
            'acted' => $acted,
            'timeout' => $detail->timeout,
            'warranty_start' => $detail->warranty_start,
            'is_return' => $detail->is_return,
            'boot_time' => $bootTime,
            'run_time' => $runTime,
            'create_time' => Carbon::parse($detail->create_time)->toDateTimeString(),
            'update_time' => Carbon::parse($detail->update_time)->toDateTimeString(),
            'images' => $qfImages,
            'image_paths' => $imagePaths,
            'histories' => $qfHistories
        ];
        return $result;
    }

    // 关闭问题反馈
    public static function close($id)
    {
        $qf = QuestionFeedback::find($id);
        if (empty($qf)) {
            throw new \Exception('问题反馈不存在');
        }

        // 状态判断
        if (!$qf->btn_close) {
            throw new \Exception('当前状态不允许关闭');
        }

        $resolved = intval(request('resolved', ''));
        if ($resolved) {
            $resolved = 1;
        }
        $resolveContent = trim(request('resolve_content', ''));

        $qf->status = self::STATUS_CLOSED;
        $qf->resolved = $resolved;
        $qf->resolve_time = Carbon::now()->toDateTimeString();
        $qf->resolve_content = $resolveContent;
        $qf->saveOrFail();

        $user = registry('user');
        $historyComment = [
            'user_id' => $user->id ?? 0,
            'user_name' => $user->realname ?? '',
            'comment' => self::COMMENT_CLOSED
        ];
        $historyData = [
            'qf_id' => $id,
            'user_id' => $user->id ?? '',
            'status' => self::STATUS_CLOSED,
            'comment' => json_encode($historyComment)
        ];
        $history = new History();
        $history->fill($historyData);
        $history->saveOrFail();

        /**
         * 消息推送
         *  -> 创建人
         */
        $qfId = $qf->id;
        $acceptId = $qf->user_id;
        $actorUserName = $user->manager_name ?? '';
        $actorRoleName = self::ROLE_MANAGER;
        $title = self::TITLE_NOTIFY;
        $content = self::CONTENT_CLOSED;
        self::notifyMessage($qfId, $acceptId, $actorUserName, $actorRoleName, $title, $content);

        return self::getDetail($id);
    }

    /**
     * 反馈审核(区域经理审核， 反馈至品质部)
     * 当前审核数据的区域经理或提交人所在区域的区域经理可审核
     * @param $id
     * @return array
     * @throws \Throwable
     */
    public static function audit($id)
    {
        $user = registry('user');
        $qf = QuestionFeedback::find($id);
        if (empty($qf)) {
            throw new \Exception('该质量反馈不存在');
        }
        if (!$qf->btn_engineer_to) {
            throw new \Exception('当前状态不允许反馈');
        }

        $resolved = intval(request('resolved', ''));
        $resolveContent = trim(strval(request('resolve_content', '')));
        $quantityUserId = intval(request('quantity_user_id', ''));
        $quantityUser = UserModel::find($quantityUserId);
        if (empty($quantityUser)) {
            throw new \Exception('所选品质工程师不存在');
        }
        if ($resolved) {
            $resolved = 1;
        }

        $qf->resolved = $resolved;
        $qf->resolve_content = $resolveContent;
        $qf->resolve_time = Carbon::now()->toDateTimeString();
        $qf->status = self::STATUS_AUDIT;
        $qf->quantity_user_id = $quantityUserId;
        $qf->quantity_user_name = $quantityUser->realname ?? '';
        $qf->suggestion_manager = $resolveContent;
        $qf->suggestion_manager_time = Carbon::now()->toDateTimeString();
        $qf->saveOrFail();

        $historyComment = [
            'qf_id' => $id,
            'user_id' => $user->id,
            'user_name' => $user->realname,
            'comment' => self::COMMENT_AUDIT
        ];
        $historyData = [
            'qf_id' => $id,
            'user_id' => $user->id,
            'status' => self::STATUS_AUDIT,
            'comment' => json_encode($historyComment)
        ];

        $history = new History();
        $history->fill($historyData);
        $history->saveOrFail();

        /**
         * 消息推送
         *  -> 品质工程师
         */
        $qfId = $qf->id;
        $acceptId = $quantityUserId;
        $actorUserName = $user->realname ?? '';
        $actorRoleName = self::ROLE_MANAGER;
        $title = self::TITLE_NOTIFY;
        $content = self::CONTENT_UN_AUDIT;
        self::notifyMessage($qfId, $acceptId, $actorUserName, $actorRoleName, $title, $content);

        return self::getDetail($id);
    }

    // 品质工程师审核
    public static function quantityAudit($id)
    {
        $qf = QuestionFeedback::find($id);
        if (empty($qf)) {
            throw new \Exception('质量反馈不存在');
        }

        if (!$qf->btn_quantity_audit) {
            throw new \Exception('当前状态不允许审核');
        }

        $data = request()->getContent();
        $arr = json_decode($data, true);

        $questionType = trim(strval($arr['question_type'] ?? ''));
        $questionTypeDetail = trim(strval($arr['question_type_detail'] ?? ''));
        if (!$questionType || !$questionTypeDetail) {
            throw new \Exception('请选择问题归类');
        }
        $exceptionLevel = trim(strval($arr['exception_level'] ?? ''));
        if (!$exceptionLevel) {
            throw new \Exception('请选择异常等级');
        }
        $chargeUserId = intval($arr['charge_user_id'] ?? 0);
        $chargeUser = UserModel::find($chargeUserId);
        if (empty($chargeUser)) {
            // throw new \Exception('问题责任人异常');
        }
        $chargeUserName = $chargeUser->realname ?? '';
        $detectivity = trim(strval($arr['detectivity'] ?? ''));
        $improve = trim(strval($arr['improve'] ?? ''));
        $measureReason = trim(strval($arr['measure_reason'] ?? ''));
        $measureTempScene = trim(strval($arr['measure_temp_scene'] ?? ''));

        $isReturn = intval(request('is_return', ''));
        if ($isReturn) {
            $isReturn = 1;
        }

        $deptId = $chargeUser->dept_id ?? 0;
        $dept = DeptModel::find($deptId);
        $deptName = $dept->name ?? '';

        $qf->question_type = $questionType;
        $qf->question_type_detail = $questionTypeDetail;
        $qf->exception_level = $exceptionLevel;
        $qf->charge_user_id = $chargeUserId;
        $qf->charge_user_name = $chargeUserName;
        $qf->detectivity = $detectivity;
        $qf->improve = $improve;
        $qf->measure_reason = $measureReason;
        $qf->measure_temp_scene = $measureTempScene;
        $qf->dept_id = $deptId;
        $qf->dept_name = $deptName;
        $qf->is_return = $isReturn;
        $qf->quantity_update_time = Carbon::now()->toDateTimeString();

        $qf->status = self::STATUS_AUDIT_QUANTITY;
        $qf->saveOrFail();

        $user = registry('user');
        $historyComment = [
            'user_id' => $user->id ?? 0,
            'user_name' => $user->realname ?? '',
            'comment' => self::COMMENT_QUANTITY_AUDIT
        ];
        $historyData = [
            'qf_id' => $id,
            'user_id' => $user->id ?? '',
            'status' => self::STATUS_AUDIT_QUANTITY,
            'comment' => json_encode($historyComment)
        ];
        $history = new History();
        $history->fill($historyData);
        $history->saveOrFail();

        /**
         * 消息推送
         *  -> 反馈者
         */
        $qfId = $qf->id;
        $acceptId = intval($qf->user_id ?? 0);;
        $actorUserName = $user->realname ?? '';
        $actorRoleName = self::ROLE_QUANTITY_MANAGER;
        $title = self::TITLE_NOTIFY;
        $content = self::CONTENT_QUANTITY;
        self::notifyMessage($qfId, $acceptId, $actorUserName, $actorRoleName, $title, $content);

        return self::getDetail($id);
    }

    // 工程师处理
    public static function action($id)
    {
        $qf = QuestionFeedback::find($id);
        if (empty($qf)) {
            throw new \Exception('问题反馈不存在');
        }
        if (!$qf->btn_engineer_process) {
            throw new \Exception('当前状态不允许处理');
        }
        $resolved = intval(request('resolved', ''));
        if ($resolved) {
            $resolved = 1;
        }
        $user = registry('user');

        $qf->status = self::STATUS_PROCESSED;
        if ($resolved) {
            $qf->resolved = $resolved;
            $qf->resolve_time = Carbon::now()->toDateTimeString();
        }
        $qf->saveOrFail();
        $historyComment = [
            'user_id' => $user->id ?? 0,
            'user_name' => $user->realname ?? '',
            'comment' => self::COMMENT_ACTION
        ];
        $historyData = [
            'qf_id' => $id,
            'user_id' => $user->id ?? '',
            'status' => self::STATUS_PROCESSED,
            'comment' => json_encode($historyComment)
        ];
        $history = new History();
        $history->fill($historyData);
        $history->saveOrFail();

        /**
         * 消息推送
         *  -> 区域经理
         */
        $qfId = $qf->id;
        $acceptId = intval($qf->manager_id ?? 0);;
        $actorUserName = $user->realname ?? '';
        $actorRoleName = self::ROLE_ENGINEER;
        $title = self::TITLE_NOTIFY;
        $content = self::CONTENT_UN_CLOSED;
        self::notifyMessage($qfId, $acceptId, $actorUserName, $actorRoleName, $title, $content);

        return self::getDetail($id);
    }


    /**
     * @param int $id 质量反馈ID
     * @param int $acceptId 接收人ID
     * @param string $actorUserName 操作人姓名
     * @param string $actorRoleName 操作人角色
     * @param string $title 标题
     * @param string $content 内容
     * @return void
     */
    private static function notifyMessage(int $id, int $acceptId, string $actorUserName, string $actorRoleName, string $title, string $content)
    {
        if (!$acceptId) {
            return;
        }

        $qf = QuestionFeedback::find($id);
        if (empty($qf)) {
            return;
        }
        if ($qf->wo_id) {
            $type = '工单反馈';
        } else {
            $type = '问题反馈';
        }
        $userIds = [$acceptId];
        $businessId = $id;
        $businessType = NotificationRepo::TYPE_QUESTION_FEEDBACK;
        $comment = [
            'actor_role_name' => $actorRoleName,
            'actor_user_name' => $actorUserName,
            'type' => $type
        ];
        NotificationRepo::multiStore($userIds, $businessId, $businessType, $title, $content, json_encode($comment));
    }

    // 质量反馈数据验证
    private static function validate()
    {
        $user = registry('user');
        $data = request()->getContent();
        $arr = json_decode($data, true);

        $deptId = $user->dept_id;
        $managers = (new DeptService())->getManagersByDeptId($deptId, false);
        $manager = $managers[0] ?? [];

        $projectId = intval($arr['project_id'] ?? 0);
        $woId = intval($arr['wo_id'] ?? 0);
        $workOrderNumber = '';
        $checked = intval($arr['checked'] ?? 0);
        $orderNumber = trim($arr['order_number'] ?? '');
        $questionLevel = trim($arr['question_level'] ?? '');
        $questionType = trim($arr['question_type'] ?? '');
        $description = trim($arr['description'] ?? '');
        $reason = trim($arr['reason'] ?? '');
        $suggestion = trim($arr['suggestion'] ?? '');
        $measureTemp = trim($arr['measure_temp'] ?? '');
        $isQuality = intval($arr['is_quality'] ?? '');
        $productId = intval($arr['product_id'] ?? '');
        $quantity = intval($arr['quantity'] ?? '');
        $productionBase = trim($arr['production_base'] ?? '');
        $questionTypeDetail = trim($arr['question_type_detail'] ?? '');
        $bomReplace = intval($arr['bom_replace'] ?? '');
        $product = null;

        $bootTime = trim(request('boot_time', ''));
        if ($bootTime) {
            try {
                $bootTime = Carbon::parse($bootTime)->toDateString();
            } catch (\Exception $e) {
                $bootTime = '';
            }
        }

        // 项目或工单提交验证
        if (!$projectId && !$woId) {
            // throw new \Exception('请选择是项目问题还是工单问题');
        }

        if ($woId) {
            $workOrder = WorkOrder::find($woId);
            if (empty($workOrder)) {
                throw new \Exception('工单数据不存在');
            }
            $workOrderNumber = $workOrder->wo_number;
            $isQuality = 1;
            if (!$productId) {
                throw new \Exception('请选择设备');
            }
            if (empty($productionBase)) {
                throw new \Exception('请选择生产基地');
            }
            $product = Product::find($productId);
            if (empty($product)) {
                throw new \Exception('设备不存在');
            }
            if ($quantity < 1) {
                throw new \Exception('异常数量错误');
            }
        }

        $project = null;
        if ($projectId) {
            $project = Project::find($projectId);
            if (empty($project)) {
                throw new \Exception('项目数据不存在');
            }
            if ($isQuality) {
                $isQuality = 1;
            }
            if ($isQuality && !$productId) {
                throw new \Exception('请选择设备');
            }
            if ($isQuality && !$productionBase) {
                throw new \Exception('请选择生产基地');
            }
            if ($isQuality) {
                $product = Product::find($productId);
                if (empty($product)) {
                    throw new \Exception('设备不存在');
                }
            }
            if ($isQuality && $quantity < 1) {
                throw new \Exception('异常数量错误');
            }
        }

        if (!$orderNumber) {
            throw new \Exception('请输入订单号');
        }

        if (empty($questionLevel)) {
            throw new \Exception('请选择问题等级');
        }
        if (empty($questionType)) {
            throw new \Exception('请选择问题归类');
        }
        if (empty($questionTypeDetail)) {
            throw new \Exception('请选择问题归类明细');
        }
        if (empty($description)) {
            throw new \Exception('请输入问题描述');
        }
        if (empty($reason)) {
            throw new \Exception('请输入原因分析');
        }
        if (empty($measureTemp)) {
            throw new \Exception('请输入临时措施');
        }

        $productDate = '';
        $productNumber = trim(request('product_number', '')) ?: $product->product_number ?? '';
        $customerName = trim(request('customer_name', '')) ?: $product->customer->name ?? '';
        // 202304087698099
        preg_match_all("/20\d{6}/", $productNumber, $dates);
        $date = $dates[0][0] ?? '';
        if ($date) {
            $productDate = substr($date, 0, 4) . '年' . substr($date, 4, 2) . '月' . substr($date, 6, 2) . '日';
        }

        $images = $arr['images'] ?? [];
        $userId = $user->id ?? 0;
        $userName = $user->realname ?? '';
        $status = self::STATUS_CREATE;
        $historyComment = [
            'user_id' => $userId,
            'user_name' => $userName,
            'comment' => "提交了问题反馈"
        ];

        $result = [
            'main' => [
                'qf_number' => self::generateNumber(),
                'user_id' => $userId,
                'user_name' => $userName,
                'wo_id' => $woId,
                'wo_number' => $workOrderNumber,
                'project_id' => $projectId,
                'project_number' => $project->project_number ?? '',
                'order_number' => $orderNumber,
                'checked' => $checked ? 1 : 0,
                'is_quality' => $isQuality,
                'product_id' => $productId,
                'product_name' => request('product_name') ?: $product->name ?? '',
                'product_number' => $productNumber,
                'product_date' => $productDate,
                'quantity' => $quantity,
                'production_base' => $productionBase,
                'question_level' => $questionLevel,
                'question_type' => $questionType,
                'question_type_detail' => $questionTypeDetail,
                'bom_replace' => $bomReplace,
                'customer_name' => $customerName,
                'manager_id' => $manager['id'] ?? $userId,
                'manager_name' => $manager['realname'] ?? $userName,
                'description' => $description,
                'reason' => $reason,
                'measure_temp' => $measureTemp,
                'suggestion' => $suggestion,
                'warranty_start' => $product->warranty_start ?? '',
                'status' => $status,
                'boot_time' => $bootTime
            ],
            'images' => $images,
            'history' => [
                'user_id' => $userId,
                'status' => $status,
                'comment' => json_encode($historyComment)
            ]
        ];

        return $result;
    }

    private static function generateNumber()
    {
        $number = date('Ymd') . Str::random(8);
        $count = QuestionFeedback::byNumber($number)->count();
        if ($count) {
            return self::generateNumber();
        }
        return $number;
    }
}